---
title: Combobox
description: Using the combobox machine in your project.
package: "@zag-js/combobox"
---

A combobox is an input widget with an associated popup that enables users to
select a value from a collection of possible values.

<Resources pkg="@zag-js/combobox" />

<Showcase id="Combobox" />

**Features**

- Support for selecting multiple values
- Support for disabled options
- Support for custom user input values
- Support for mouse, touch, and keyboard interactions
- Keyboard support for opening the combo box list box using the arrow keys,
  including automatically focusing the first or last item accordingly

## Installation

To use the combobox machine in your project, run the following command in your
command line:

<CodeSnippet id="combobox/installation.mdx" />

## Anatomy

To set up the combobox correctly, you'll need to understand its anatomy and how
we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.

<Anatomy id="combobox" />

## Usage

First, import the combobox package into your project

```jsx
import * as combobox from "@zag-js/combobox"
```

The combobox package exports these functions:

- `machine` — The state machine logic for the combobox widget.
- `connect` — The function that translates the machine's state to JSX attributes
  and event handlers.
- `collection` - The function that creates a
  [collection interface](/overview/collection) from an array of items.

Next, import the required hooks and functions for your framework and use the
combobox machine in your project 🔥

<CodeSnippet id="combobox/usage.mdx" />

### Setting the initial value

To set the initial value of the combobox, pass the `defaultValue` property to
the machine's context.

```jsx {13}
const collection = combobox.collection({
  items: [
    { label: "Nigeria", value: "ng" },
    { label: "Ghana", value: "gh" },
    { label: "Kenya", value: "ke" },
    //...
  ],
})

const service = useMachine(combobox.machine, {
  id: useId(),
  collection,
  defaultValue: ["ng"],
})
```

### Controlled combobox

To control the value programmatically, pass the `value` and `onValueChange`
properties to the machine function.

<CodeSnippet id="combobox/controlled.mdx" />

### Selecting multiple values

To allow selecting multiple values, set the `multiple` property in the machine's
context to `true`.

```jsx {4}
const service = useMachine(combobox.machine, {
  id: useId(),
  collection,
  multiple: true,
})
```

### Using a custom object format

By default, the combobox collection expects an array of items with `label` and
`value` properties. To use a custom object format, pass the `itemToString` and
`itemToValue` properties to the collection function.

- `itemToString` — A function that returns the string representation of an item.
  Used to compare items when filtering.
- `itemToValue` — A function that returns the unique value of an item.
- `itemToDisabled` — A function that returns the disabled state of an item.

```jsx
const collection = combobox.collection({
  // custom object format
  items: [
    { id: 1, fruit: "Banana", available: true, quantity: 10 },
    { id: 2, fruit: "Apple", available: false, quantity: 5 },
    { id: 3, fruit: "Orange", available: true, quantity: 3 },
    //...
  ],
  // convert item to string
  itemToString(item) {
    return item.fruit
  },
  // convert item to value
  itemToValue(item) {
    return item.id
  },
  // convert item to disabled state
  itemToDisabled(item) {
    return !item.available || item.quantity === 0
  },
})

// use the collection
const service = useMachine(combobox.machine, {
  id: useId(),
  collection,
})
```

### Rendering the selected values outside the combobox

By default, the selected values of a combobox are displayed in the input
element, when selecting multiple items, it is a better UX to render the selected
value outside the combobox.

To achieve this you need to:

- Set the `selectionBehavior` to `clear`, which clears the input value when an
  item is selected.
- Set the `multiple` property to `true` to allow selecting multiple values.
- Render the selected values outside the combobox.

```jsx {4-6}
const service = useMachine(combobox.machine, {
  id: useId(),
  collection,
  selectionBehavior: "clear",
  multiple: true,
})
```

### Disabling the combobox

To make a combobox disabled, set the context's `disabled` property to `true`

```jsx {2}
const service = useMachine(combobox.machine, {
  disabled: true,
})
```

### Disabling an option

To make a combobox option disabled, pass the `isItemDisabled` property to the
collection function.

```jsx {6-8}
const service = useMachine(combobox.machine, {
  id: useId(),
  collection: combobox.collection({
    items: countries,
    isItemDisabled(item) {
      return item.disabled
    },
  }),
})
```

### Close on select

This behaviour ensures that the menu is closed when an option is selected and is
`true` by default. It's only concerned with when an option is selected with
pointer or enter key. To disable the behaviour, set the `closeOnSelect` property
in the machine's context to `false`.

```jsx {2}
const service = useMachine(combobox.machine, {
  closeOnSelect: false,
})
```

### Making the combobox readonly

To make a combobox readonly, set the context's `readOnly` property to `true`

```jsx {2}
const service = useMachine(combobox.machine, {
  readOnly: true,
})
```

### Listening for highlight changes

When an option is highlighted with the pointer or keyboard, use the
`onHighlightChange` property to listen for this change and do something with it.

```jsx {3-6}
const service = useMachine(combobox.machine, {
  id: useId(),
  onHighlightChange(details) {
    // details => { value: string | null; item: CollectionItem | null }
    console.log(details)
  },
})
```

### Listening for value changes

When an item is selected, use `onValueChange` property to listen for this change
and do something with it.

```jsx {3-6}
const service = useMachine(combobox.machine, {
  onValueChange(details) {
    // details => { value: string[]; items: CollectionItem[] }
    console.log(details)
  },
})
```

### Usage within forms

The combobox works when placed within a form and the form is submitted. We
achieve this by:

- ensuring we emit the input event as the value changes.
- adding a `name` attribute to the input so the value can be accessed in the
  `FormData`.

To get this feature working you need to pass a `name` option to the context.

```jsx {2}
const service = useMachine(combobox.machine, {
  name: "countries",
})
```

### Allowing custom values

By default, the combobox only allows selecting values from the collection. To
allow custom values, set the `allowCustomValue` property in the machine's
context to `true`.

```jsx {2}
const service = useMachine(combobox.machine, {
  allowCustomValue: true,
})
```

## Styling guide

Earlier, we mentioned that each combobox part has a `data-part` attribute added
to them to select and style them in the DOM.

### Open and closed state

When the combobox is open or closed, the `data-state` attribute is added to the
content,control, input and control parts.

```css
[data-part="control"][data-state="open|closed"] {
  /* styles for control open or state */
}

[data-part="input"][data-state="open|closed"] {
  /* styles for control open or state */
}

[data-part="trigger"][data-state="open|closed"] {
  /* styles for control open or state */
}

[data-part="content"][data-state="open|closed"] {
  /* styles for control open or state */
}
```

### Focused State

When the combobox is focused, the `data-focus` attribute is added to the control
and label parts.

```css
[data-part="control"][data-focus] {
  /* styles for control focus state */
}

[data-part="label"][data-focus] {
  /* styles for label focus state */
}
```

### Disabled State

When the combobox is disabled, the `data-disabled` attribute is added to the
label, control, trigger and option parts.

```css
[data-part="label"][data-disabled] {
  /* styles for label disabled state */
}

[data-part="control"][data-disabled] {
  /* styles for control disabled state */
}

[data-part="trigger"][data-disabled] {
  /* styles for trigger disabled state */
}

[data-part="item"][data-disabled] {
  /* styles for item disabled state */
}
```

### Invalid State

When the combobox is invalid, the `data-invalid` attribute is added to the root,
label, control and input parts.

```css
[data-part="root"][data-invalid] {
  /* styles for root invalid state */
}

[data-part="label"][data-invalid] {
  /* styles for label invalid state */
}

[data-part="control"][data-invalid] {
  /* styles for control invalid state */
}

[data-part="input"][data-invalid] {
  /* styles for input invalid state */
}
```

### Selected State

When a combobox item is selected, the `data-state` attribute is added to the
item part.

```css
[data-part="item"][data-state="checked|unchecked"] {
  /* styles for item selected state */
}
```

### Highlighted State

When a combobox item is highlighted, the `data-highlighted` attribute is added
to the item part.

```css
[data-part="item"][data-highlighted] {
  /* styles for item highlighted state */
}
```

## Methods and Properties

### Machine Context

The combobox machine exposes the following context properties:

<ContextTable name="combobox" />

### Machine API

The combobox `api` exposes the following methods:

<ApiTable name="combobox" />

### Data Attributes

<DataAttrTable name="combobox" />

### CSS Variables

<CssVarTable name="combobox" />

## Accessibility

Adheres to the
[Combobox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).

### Keyboard Interactions

<KeyboardTable name="combobox" />
